package com.markbuikema.juliana32.util;

import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import android.content.Context;
import android.text.format.DateUtils;
import android.util.Log;

import com.markbuikema.juliana32.R;

public class DateTimeUtils extends DateUtils {

	private static String mTimestampLabelYesterday;
	private static String mTimestampLabelToday;
	private static String mTimestampLabelJustNow;
	private static String mTimestampLabelMinutesAgo;
	private static String mTimestampLabelHoursAgo;

	private static Context context;
	private static DateTimeUtils instance;

	/**
	 * Singleton contructor, needed to get access to the application context &
	 * strings for i18n
	 * 
	 * @param context
	 *            Context
	 * @return DateTimeUtils singleton instanec
	 * @throws Exception
	 */
	public static DateTimeUtils getInstance(Context ctx) {
		context = ctx;
		if (instance == null) {
			instance = new DateTimeUtils();
			mTimestampLabelYesterday = context.getResources().getString(R.string.timestamp_yesterday);
			mTimestampLabelToday = context.getResources().getString(R.string.timestamp_today);
			mTimestampLabelJustNow = context.getResources().getString(R.string.timestamp_just_now);
			mTimestampLabelMinutesAgo = context.getResources().getString(R.string.timestamp_minutes_ago);
			mTimestampLabelHoursAgo = context.getResources().getString(R.string.timestamp_hours_ago);
		}
		return instance;
	}

	/**
	 * Checks if the given date is yesterday.
	 * 
	 * @param date
	 *            - Date to check.
	 * @return TRUE if the date is yesterday, FALSE otherwise.
	 */
	public static boolean isYesterday(long date) {

		final Calendar currentDate = Calendar.getInstance();
		currentDate.setTimeInMillis(date);

		final Calendar yesterdayDate = Calendar.getInstance();
		yesterdayDate.add(Calendar.DATE, -1);

		return yesterdayDate.get(Calendar.YEAR) == currentDate.get(Calendar.YEAR) && yesterdayDate.get(Calendar.DAY_OF_YEAR) == currentDate.get(Calendar.DAY_OF_YEAR);
	}

	public static String[] weekdays = new String[] { "", "Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag" };
	public static final long DAY_IN_MS = 1000 * 60 * 60 * 24;
	public static final long GAME_IN_MS = 1000 * 60 * 105;

	/**
	 * Displays a user-friendly date difference string
	 * 
	 * @param timedate
	 *            Timestamp to format as date difference from now
	 * @return Friendly-formatted date diff string
	 */
	public String getTimeDiffString(long timedate) {
		Calendar startDateTime = Calendar.getInstance();
		Calendar endDateTime = Calendar.getInstance();
		endDateTime.setTimeInMillis(timedate);
		long milliseconds1 = startDateTime.getTimeInMillis();
		long milliseconds2 = endDateTime.getTimeInMillis();
		long diff = milliseconds1 - milliseconds2;

		long hours = diff / (60 * 60 * 1000);
		long minutes = diff / (60 * 1000);
		minutes = minutes - 60 * hours;

		boolean isToday = DateTimeUtils.isToday(timedate);
		boolean isYesterday = DateTimeUtils.isYesterday(timedate);

		if (hours > 0 && hours < 12)
			return String.format(mTimestampLabelHoursAgo, hours);
		else if (hours <= 0) {
			if (minutes > 0)
				return String.format(mTimestampLabelMinutesAgo, minutes);
			else
				return mTimestampLabelJustNow;
		} else if (isToday)
			return mTimestampLabelToday;
		else if (isYesterday)
			return mTimestampLabelYesterday;
		else if (startDateTime.getTimeInMillis() - timedate < DAY_IN_MS * 6)
			return weekdays[endDateTime.get(Calendar.DAY_OF_WEEK)];
		else
			return getDateString(timedate);
	}

	private static String getDateString(long timedate) {
		GregorianCalendar date = new GregorianCalendar();
		date.setTimeInMillis(timedate);
		String output = date.get(GregorianCalendar.DAY_OF_MONTH) + " " + getMonthInDutch(date.get(GregorianCalendar.MONTH));
		if (new GregorianCalendar().get(GregorianCalendar.YEAR) != date.get(GregorianCalendar.YEAR))
			output += " " + date.get(GregorianCalendar.YEAR);

		return output;

	}

	public static String getMonthInDutch(int month) {
		switch (month) {
		case 1:
			return "februari";
		case 2:
			return "maart";
		case 3:
			return "april";
		case 4:
			return "mei";
		case 5:
			return "juni";
		case 6:
			return "juli";
		case 7:
			return "augustus";
		case 8:
			return "september";
		case 9:
			return "oktober";
		case 10:
			return "november";
		case 11:
			return "december";
		default:
			return "januari";

		}

	}

	public static String getDayOfWeekInDutch(int day) {
		switch (day) {
		case GregorianCalendar.MONDAY:
			return "maandag";
		case GregorianCalendar.TUESDAY:
			return "dinsdag";
		case GregorianCalendar.WEDNESDAY:
			return "woensdag";
		case GregorianCalendar.THURSDAY:
			return "donderdag";
		case GregorianCalendar.FRIDAY:
			return "vrijdag";
		case GregorianCalendar.SUNDAY:
			return "zondag";
		default:
			return "zaterdag";
		}
	}

	public static String getDateString(Context ctx, GregorianCalendar date) {
		return DateTimeUtils.getInstance(ctx).getTimeDiffString(date.getTimeInMillis());
	}

	private static enum Month {
		JANUARI,
		FEBRUARI,
		MAART,
		APRIL,
		MEI,
		JUNI,
		JULI,
		AUGUSTUS,
		SEPTEMBER,
		OKTOBER,
		NOVEMBER,
		DECEMBER
	}

	public static GregorianCalendar parseDate(String websiteDate) {
		int dateDay = Integer.parseInt(websiteDate.substring(0, 2));
		int dateYear = Integer.parseInt(websiteDate.substring(websiteDate.length() - 4, websiteDate.length()));
		int dateMonth = 0;
		Month month = Month.valueOf(websiteDate.split(" ")[1].toUpperCase());
		switch (month) {
		case FEBRUARI:
			dateMonth = 1;
			break;
		case MAART:
			dateMonth = 2;
			break;
		case APRIL:
			dateMonth = 3;
			break;
		case MEI:
			dateMonth = 4;
			break;
		case JUNI:
			dateMonth = 5;
			break;
		case JULI:
			dateMonth = 6;
			break;
		case AUGUSTUS:
			dateMonth = 7;
			break;
		case SEPTEMBER:
			dateMonth = 8;
			break;
		case OKTOBER:
			dateMonth = 9;
			break;
		case NOVEMBER:
			dateMonth = 10;
			break;
		case DECEMBER:
			dateMonth = 11;
			break;
		default:
			dateMonth = 0;
			break;
		}

		return new GregorianCalendar(dateYear, dateMonth, dateDay);
	}

	public static GregorianCalendar fbStringToDate(String dateString) {
		try {
			String yearString = dateString.substring(0, 4);
			String monthString = dateString.substring(5, 7);
			String dayString = dateString.substring(8, 10);
			String hourString = dateString.substring(11, 13);
			String minuteString = dateString.substring(14, 16);
			String secondString = dateString.substring(17, 19);
			String timezoneString = dateString.substring(19, 22);
			GregorianCalendar createdAt = new GregorianCalendar();
			createdAt.setTimeZone(TimeZone.getTimeZone("GMT" + timezoneString + ":00"));
			createdAt.set(Integer.parseInt(yearString), Integer.parseInt(monthString) - 1, Integer.parseInt(dayString), Integer.parseInt(hourString), Integer.parseInt(minuteString),
					Integer.parseInt(secondString));
			return createdAt;

		} catch (IndexOutOfBoundsException e) {
			Log.e("dateparser","Could not parse " + dateString);
			return null;
		}
	}

	public static long parseKnvbDate(String date, String time) {
		String yearString = date.substring(0, 4);
		String monthString = date.substring(5, 7);
		String dayString = date.substring(8, 10);
		String hourString = time.substring(0, 2);
		String minuteString = time.substring(2, 4);
		GregorianCalendar output = new GregorianCalendar();
		output.set(Integer.parseInt(yearString), Integer.parseInt(monthString) - 1, Integer.parseInt(dayString), Integer.parseInt(hourString), Integer.parseInt(minuteString));
		return output.getTimeInMillis();

	}

	public static String getDutchDateString(GregorianCalendar cal) {
		DecimalFormat df = new DecimalFormat("00");

		return getDayOfWeekInDutch(cal.get(GregorianCalendar.DAY_OF_WEEK)) + " " + cal.get(GregorianCalendar.DAY_OF_MONTH) + " " + getMonthInDutch(cal.get(GregorianCalendar.MONTH)) + ", "
				+ df.format(cal.get(GregorianCalendar.HOUR_OF_DAY)) + ":" + df.format(cal.get(GregorianCalendar.MINUTE));
	}

	public static String getWeekDescription(int week) {
		GregorianCalendar gc = new GregorianCalendar();
		gc.set(GregorianCalendar.MONTH, 0);
		gc.set(GregorianCalendar.DAY_OF_MONTH, 1);
		gc.set(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.MONDAY);
		long newTime = gc.getTimeInMillis() + (week - 2) * Constants.WEEK_MILLISECONDS;
		gc.setTimeInMillis(newTime);

		String firstDay = gc.get(GregorianCalendar.DAY_OF_MONTH) + " " + DateTimeUtils.getMonthInDutch(gc.get(GregorianCalendar.MONTH));
		newTime = gc.getTimeInMillis() + Constants.SIX_DAYS_MILLISECONDS;
		gc.setTimeInMillis(newTime);
		String lastDay = gc.get(GregorianCalendar.DAY_OF_MONTH) + " " + DateTimeUtils.getMonthInDutch(gc.get(GregorianCalendar.MONTH));

		return firstDay + " - " + lastDay;
	}
}